const assert = require('assert').strict;
const PhoenixError = require('../../models/phoenix-error');
const analyzeTemplate = require('../../models/analyze-templates');
const middleware = require('./../middleware');
const utility = require('../../models/utility');
const License = require('../../models/mongo/license');

function createTemplate(req, res, next) {
  const {
    name,
    languages,
    ruleIds,
    description,
  } = req.body;
  (async () => {
    const creatorId = req.$me._id;
    const licensesLanguages = (await License.find({}, ['language']).lean())[0].language;
    assert.ok(languages && languages.length,
      new PhoenixError('invalid request', 'need languages array'));
    assert.ok(languages.every((item) => {
      if (item === 'c++') {
        return licensesLanguages.includes('c/c++');
      }
      return licensesLanguages.includes(item);
    }),
    new PhoenixError('invalid request', `language can only be ${licensesLanguages}`));
    assert.ok(name, new PhoenixError('invalid request', 'need name'));
    assert.ok(ruleIds && ruleIds.length, new PhoenixError('invalid request', 'need rules'));
    let { userDefined } = req.body || {};
    if (userDefined && utility.isArrayType(userDefined)) {
      userDefined = userDefined.reduce((pre, item) => {
        pre[item.ruleId] = { level: item.level };
        return pre;
      }, {});
    }
    const created = await analyzeTemplate.createTemplate({
      creatorId,
      name,
      languages,
      rules: ruleIds,
      description,
      userDefined,
    });
    res.json(created);
  })()
    .catch((err) => {
      if (err.code === 11000) {
        next(new PhoenixError('conflict', `name '${name}' already exists`));
      } else {
        next(new PhoenixError(err));
      }
    });
}

function deleteTemplate(req, res, next) {
  (async () => {
    const { templateId } = req.params;
    const creatorId = req.$me._id;
    await analyzeTemplate.deleteTemplate(templateId, creatorId);
    res.status(204).json();
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function updateTemplate(req, res, next) {
  (async () => {
    const { templateId } = req.params;
    const creatorId = req.$me._id;
    const updates = utility.selectFields(req.body, ['languages', 'name', 'ruleIds', 'description', 'userDefined']);
    if (Object.keys(updates).includes('ruleIds')) {
      updates.rules = updates.ruleIds;
      delete updates.ruleIds;
    }
    const ret = await analyzeTemplate.updateTemplate(templateId, updates, creatorId);
    res.json(ret.toObject());
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getTemplate(req, res, next) {
  (async () => {
    const { templateId } = req.params;
    const creatorId = req.$me._id;
    const template = await analyzeTemplate.getTemplate(templateId, creatorId);
    if (!template) {
      throw new PhoenixError('not found', `template id ${templateId} not found`);
    }
    const ret = template.toObject();
    ret.ruleIds = ret.rules;
    delete ret.rules;
    res.json(ret);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getTemplates(req, res, next) {
  (async () => {
    const creatorId = req.$me._id;
    let {
      page,
      perPage,
      languages,
      name,
    } = req.query;
    page = parseInt(page, 10) || 1;
    perPage = parseInt(perPage, 10) || 10;
    languages = languages ? [].concat(languages) : undefined;
    name = name || undefined;
    const [templates, total] = await analyzeTemplate.getTemplates(creatorId, {
      page,
      pageSize: perPage,
      languages,
      name,
    });

    res.json({
      templates: templates.map((item) => ({
        ...item.toObject(),
        createAt: item._id.generationTime * 1000,
      })),
      pagination: {
        page,
        perPage,
        total,
      },
    });
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * Export model definition object.
 */
module.exports = (app, prefix) => {
  const allTemplateURL = `${prefix}/static-analyze/templates.json`;
  const templateURL = `${prefix}/static-analyze/templates/:templateId.json`;

  // 创建静态检测模版
  app.post(allTemplateURL, middleware.user.requireTokenUnexpired);
  app.post(allTemplateURL, middleware.user.requireAvailable);
  app.post(allTemplateURL, middleware.user.requireTester);
  app.post(allTemplateURL, createTemplate);

  // 获取静态检测模版列表
  app.get(allTemplateURL, middleware.user.requireTokenUnexpired);
  app.get(allTemplateURL, middleware.user.requireAvailable);
  app.get(allTemplateURL, middleware.user.requireTester);
  app.get(allTemplateURL, getTemplates);

  // 删除静态检测模版
  app.delete(templateURL, middleware.user.requireTokenUnexpired);
  app.delete(templateURL, middleware.user.requireAvailable);
  app.delete(templateURL, middleware.user.requireTester);
  app.delete(templateURL, deleteTemplate);

  // 更新静态检测模版
  app.put(templateURL, middleware.user.requireTokenUnexpired);
  app.put(templateURL, middleware.user.requireAvailable);
  app.put(templateURL, middleware.user.requireTester);
  app.put(templateURL, updateTemplate);

  // 获取静态检测模版详情
  app.get(templateURL, middleware.user.requireTokenUnexpired);
  app.get(templateURL, middleware.user.requireAvailable);
  app.get(templateURL, middleware.user.requireTester);
  app.get(templateURL, getTemplate);
};
